﻿package systems.traer 
{
	import flash.display.Graphics;
	
	public class Spring implements Force
	{
		
		private var _p0:Particle;
		private var _p1:Particle;
		private var _color:uint = 0xCC0000;
		
		private var _springConstant:Number;
		private var _damping:Number;
		private var _restLength:Number
		private var _on:Boolean;
		
		public function Spring( p0:Particle, p1:Particle, springConstant:Number, damping:Number, restlength:Number) 
		{
			_p0 = p0;
			_p1 = p1;
			_restLength = restlength;
			_springConstant = springConstant;
			_damping = damping;
			on = true;
		}
		
		
		public final function length():Number
		{
			return p0.distance( p1 );
		}
		
		public final function apply():void 
		{
			if ( on && ( !p0.fixed || !p1.fixed ) )
			{
				var a2bX:Number = p0.position.x - p1.position.x;
				var a2bY:Number = p0.position.y - p1.position.y;
				var a2bZ:Number = p0.position.z - p1.position.z;
				
				var a2bDistance:Number = Math.sqrt( a2bX * a2bX + a2bY * a2bY + a2bZ * a2bZ );
				
				if ( a2bDistance == 0 )
				{
					a2bX = 0;
					a2bY = 0;
					a2bZ = 0;
				}
				else
				{
					a2bX /= a2bDistance;
					a2bY /= a2bDistance;
					a2bZ /= a2bDistance;
				}
				
			
				// spring force is proportional to how much it stretched 
				
				var springForce:Number = -( a2bDistance - restLength ) * springConstant; 
				
				
				// want velocity along line b/w a & b, damping force is proportional to this
				
				var Va2bX:Number = p0.velocity.x - p1.velocity.x;
				var Va2bY:Number = p0.velocity.y - p1.velocity.y;
				var Va2bZ:Number = p0.velocity.z - p1.velocity.z;
				
				var dampingForce:Number = -damping * ( a2bX * Va2bX + a2bY * Va2bY + a2bZ * Va2bZ );
				
				
				// forceB is same as forceA in opposite direction
				
				var r:Number = springForce + dampingForce;
				
				a2bX *= r;
				a2bY *= r;
				a2bZ *= r;
				
				if ( !p0.fixed )
				{
					//p0.force.addFromValues( a2bX, a2bY, a2bZ );
					p0.force.x += a2bX;
					p0.force.y += a2bY;
					p0.force.z += a2bZ;
					
				}
				
				if ( !p1.fixed )
				{
					//p1.force.addFromValues( -a2bX, -a2bY, -a2bZ );
					p1.force.x += -a2bX;
					p1.force.y += -a2bY;
					p1.force.z += -a2bZ;
					
				}
				
			}
			
		}
		public function get on():Boolean { return _on; }
		
		public function set on(value:Boolean):void 
		{
			_on = value;
		}
		
		public final function draw( g:Graphics, size:Number = 2 ):void
		{
			//g.lineStyle( 0, color );
			g.moveTo( p0.position.x, p0.position.y );
			g.lineTo( p1.position.x, p1.position.y );
		}
		
		
		public function get p0():Particle { return _p0; }
		
		public function set p0(value:Particle):void 
		{
			_p0 = value;
		}
		
		public function get p1():Particle { return _p1; }
		
		public function set p1(value:Particle):void 
		{
			_p1 = value;
		}
		
		public function get color():uint { return _color; }
		
		public function set color(value:uint):void 
		{
			_color = value;
		}
		
		public function get restLength():Number { return _restLength; }
		
		public function set restLength(value:Number):void 
		{
			_restLength = value;
		}
		
		public function get damping():Number { return _damping; }
		
		public function set damping(value:Number):void 
		{
			_damping = value;
		}
		
		public function get springConstant():Number { return _springConstant; }
		
		public function set springConstant(value:Number):void 
		{
			_springConstant = value;
		}
		
		
	}

}